// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#include "../../include/fxedit/fxet_stub.h"
#include "../../include/fxedit/fx_edit.h"
#include "../../include/fxedit/fxet_edit.h"

CFX_ByteString GetPDFWordString(IFX_Edit_FontMap * pFontMap, int32_t nFontIndex, FX_WORD Word, FX_WORD SubWord)
{
	ASSERT (pFontMap != NULL);

	CFX_ByteString sWord;

	if (CPDF_Font * pPDFFont = pFontMap->GetPDFFont(nFontIndex))
	{
		if (SubWord > 0)
		{
			Word = SubWord;
		}
		else
		{
			FX_DWORD dwCharCode = -1;

			if (pPDFFont->IsUnicodeCompatible())
				dwCharCode = pPDFFont->CharCodeFromUnicode(Word);
			else
				dwCharCode = pFontMap->CharCodeFromUnicode(nFontIndex, Word);

			if (dwCharCode > 0 )
			{
				pPDFFont->AppendChar(sWord, dwCharCode);
				return sWord;
			}
		}

		pPDFFont->AppendChar(sWord, Word);
	}

	return sWord;
}

static CFX_ByteString GetWordRenderString(const CFX_ByteString & strWords)
{
	if (strWords.GetLength() > 0)
		return PDF_EncodeString(strWords) + " Tj\n";

	return "";
}

static CFX_ByteString GetFontSetString(IFX_Edit_FontMap * pFontMap, int32_t nFontIndex, FX_FLOAT fFontSize)
{
	CFX_ByteTextBuf sRet;

	if (pFontMap)
	{
		CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex);

		if (sFontAlias.GetLength() > 0 && fFontSize > 0 )
			sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n";
	}

	return sRet.GetByteString();
}

CFX_ByteString IFX_Edit::GetEditAppearanceStream(IFX_Edit* pEdit, const CPDF_Point & ptOffset,
												 const CPVT_WordRange * pRange /* = NULL*/, FX_BOOL bContinuous/* = TRUE*/, FX_WORD SubWord/* = 0*/)
{
	CFX_ByteTextBuf sEditStream, sWords;

	CPDF_Point ptOld(0.0f,0.0f),ptNew(0.0f,0.0f);
	int32_t nCurFontIndex = -1;

	if (IFX_Edit_Iterator* pIterator = pEdit->GetIterator())
	{
		if (pRange)
			pIterator->SetAt(pRange->BeginPos);
		else
			pIterator->SetAt(0);

		CPVT_WordPlace oldplace;

		while (pIterator->NextWord())
		{
			CPVT_WordPlace place = pIterator->GetAt();

			if (pRange && place.WordCmp(pRange->EndPos) > 0) break;

			if (bContinuous)
			{
				if (place.LineCmp(oldplace) != 0)
				{
					if (sWords.GetSize() > 0)
					{
						sEditStream << GetWordRenderString(sWords.GetByteString());
						sWords.Clear();
					}

					CPVT_Word word;
					if (pIterator->GetWord(word))
					{
						ptNew = CPDF_Point(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y);
					}
					else
					{
						CPVT_Line line;
						pIterator->GetLine(line);
						ptNew = CPDF_Point(line.ptLine.x + ptOffset.x, line.ptLine.y + ptOffset.y);
					}

					if (ptNew.x != ptOld.x || ptNew.y != ptOld.y)
					{
						sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y << " Td\n";

						ptOld = ptNew;
					}
				}

				CPVT_Word word;
				if (pIterator->GetWord(word))
				{
					if (word.nFontIndex != nCurFontIndex)
					{
						if (sWords.GetSize() > 0)
						{
							sEditStream << GetWordRenderString(sWords.GetByteString());
							sWords.Clear();
						}
						sEditStream << GetFontSetString(pEdit->GetFontMap(),word.nFontIndex,word.fFontSize);
						nCurFontIndex = word.nFontIndex;
					}

					sWords << GetPDFWordString(pEdit->GetFontMap(),nCurFontIndex,word.Word,SubWord);
				}

				oldplace = place;
			}
			else
			{
				CPVT_Word word;
				if (pIterator->GetWord(word))
				{
					ptNew = CPDF_Point(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y);

					if (ptNew.x != ptOld.x || ptNew.y != ptOld.y)
					{
						sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y << " Td\n";
						ptOld = ptNew;
					}

					if (word.nFontIndex != nCurFontIndex)
					{
						sEditStream << GetFontSetString(pEdit->GetFontMap(),word.nFontIndex,word.fFontSize);
						nCurFontIndex = word.nFontIndex;
					}

					sEditStream << GetWordRenderString(GetPDFWordString(pEdit->GetFontMap(),nCurFontIndex,word.Word,SubWord));
				}
			}
		}

		if (sWords.GetSize() > 0)
		{
			sEditStream << GetWordRenderString(sWords.GetByteString());
			sWords.Clear();
		}
	}

	CFX_ByteTextBuf sAppStream;
	if (sEditStream.GetSize() > 0)
	{
		int32_t nHorzScale = pEdit->GetHorzScale();
		if (nHorzScale != 100)
		{
			sAppStream << nHorzScale << " Tz\n";
		}

		FX_FLOAT fCharSpace = pEdit->GetCharSpace();
		if (!FX_EDIT_IsFloatZero(fCharSpace))
		{
			sAppStream << fCharSpace << " Tc\n";
		}

		sAppStream << sEditStream;
	}

	return sAppStream.GetByteString();
}

CFX_ByteString IFX_Edit::GetSelectAppearanceStream(IFX_Edit* pEdit, const CPDF_Point & ptOffset,
							const CPVT_WordRange * pRange /*= NULL*/)
{
	CFX_ByteTextBuf sRet;

	if (pRange && pRange->IsExist())
	{
		if (IFX_Edit_Iterator* pIterator = pEdit->GetIterator())
		{
			pIterator->SetAt(pRange->BeginPos);

			while (pIterator->NextWord())
			{
				CPVT_WordPlace place = pIterator->GetAt();

				if (pRange && place.WordCmp(pRange->EndPos) > 0) break;

				CPVT_Word word;
				CPVT_Line line;
				if (pIterator->GetWord(word) && pIterator->GetLine(line))
				{
					//CPDF_Rect rcWordSel = CPDF_Rect(word.ptWord.x,line.ptLine.y + line.fLineDescent,
					//		word.ptWord.x+word.fWidth,line.ptLine.y + line.fLineAscent);

					sRet << word.ptWord.x + ptOffset.x << " " << line.ptLine.y + line.fLineDescent
						<< " " << word.fWidth << " " << line.fLineAscent - line.fLineDescent << " re\nf\n";
				}
			}
		}
	}

	return sRet.GetByteString();
}

